package voince

import (
	"fmt"
	"os"
	"sync"
	"time"

	"pingce/core/helper"
	"pingce/sdk/common"
	"pingce/sdk/soe"
	"pingce/structs"
)

type Param struct {
	AppID       string
	SecretID    string
	SecretKey   string
	Text        string
	ProxyURL    string
	AudioFile   string
	key         string
	SliceSize   int
	EvalMode    int
	RecFlag     int
	VoiceFormat int
	ShowMsg     bool
	Loop        bool
	ScoreCoeff  float64
}

var __Result []string = make([]string, 0)

type testLearn struct {
	parm    *Param
	key     string
	Channel chan string
}

func newInstance(p *Param) *testLearn {
	return &testLearn{parm: p, Channel: make(chan string, 5)}
}

func (t *testLearn) check() error {
	if helper.Empty(t.parm.AppID) {
		return fmt.Errorf("缺少腾讯云app_id")
	}

	if helper.Empty(t.parm.SecretID) {
		return fmt.Errorf("缺少腾讯云secret_id")
	}

	if helper.Empty(t.parm.SecretKey) {
		return fmt.Errorf("缺少腾讯云secret_key")
	}

	if helper.Empty(t.parm.AudioFile) {
		return fmt.Errorf("请传递音频文件")
	}

	if helper.Empty(t.parm.Text) {
		return fmt.Errorf("请传递单词或者句子")
	}

	return nil
}

func RunVoince(p *Param, run_count int) ([]string, error) {
	var wg sync.WaitGroup

	ShowMsg := p.ShowMsg
	Loop := p.Loop
	AudioFile := p.AudioFile

	testLearn := newInstance(p)
	testLearn.key = p.key
	if err := testLearn.check(); err != nil {
		return nil, err
	}

	for i := 0; i < run_count; i++ {
		helper.Msg("Main: 流数据开始启动", ShowMsg)
		wg.Add(1)

		if Loop {
			go testLearn.ProcessLoop(i, &wg, AudioFile)
		} else {
			go testLearn.ProcessOnce(i, &wg, AudioFile)
		}
	}

	helper.Msg("Main: 正等待works进程完成", ShowMsg)
	__Result = make([]string, 0)
	// 接收通道的值
	go func() {
		for info := range testLearn.Channel {
			__Result = append(__Result, info)
		}
	}()

	wg.Wait()

	helper.Msg("Main: 执行完成", ShowMsg)

	return __Result, nil
}

func (t *testLearn) ProcessLoop(id int, wg *sync.WaitGroup, file string) {
	defer wg.Done()

	for {
		err := t.process(id, file)
		if err != nil {
			return
		}
	}
}

func (t *testLearn) ProcessOnce(id int, wg *sync.WaitGroup, file string) {
	defer wg.Done()

	err := t.process(id, file)
	if err != nil {
		helper.Msg(err.Error(), true)
		return
	}
}

func (t *testLearn) process(id int, file string) error {
	audio, err := os.Open(file)
	if err != nil {
		return fmt.Errorf("文件不存在或者没有读取权限: %v\n", err)
	}

	defer func(audio *os.File) {
		err := audio.Close()
		if err != nil {
			panic(err)
		}
	}(audio)

	listener := &structs.SpeakingListener{
		ID:      id,
		Key:     t.key,
		Channel: t.Channel,
	}

	SecretID := t.parm.SecretID
	SecretKey := t.parm.SecretKey
	AppID := t.parm.AppID
	ProxyURL := t.parm.ProxyURL
	Text := t.parm.Text
	EvalMode := t.parm.EvalMode
	SliceSize := t.parm.SliceSize
	ScoreCoeff := t.parm.ScoreCoeff
	RecFlag := t.parm.RecFlag
	if SliceSize == 0 {
		SliceSize = 1600
	}
	if RecFlag == 0 {
		RecFlag = 1
	}

	// 临时秘钥鉴权需要使用带token的方式 credential := common.NewTokenCredential(SecretID, SecretKey, Token)
	credential := common.NewCredential(SecretID, SecretKey)
	recognizer := soe.NewSpeechRecognizer(AppID, credential, listener)
	recognizer.ProxyURL = ProxyURL

	fmt.Println("格式：", t.parm.VoiceFormat)

	if t.parm.VoiceFormat == 1 {
		recognizer.VoiceFormat = soe.AudioFormatWav
	} else if t.parm.VoiceFormat == 2 {
		recognizer.VoiceFormat = soe.AudioFormatMp3
		// RecFlag = 2
	} else {
		recognizer.VoiceFormat = soe.AudioFormatWav
	}

	if EvalMode == 0 {
		recognizer.RefText = "{::cmd{F_P2L=true}} " + Text
	} else {
		recognizer.RefText = "" + Text
	}

	fmt.Println("发送文本：", recognizer.RefText)

	recognizer.ServerEngineType = "16k_en"
	recognizer.ScoreCoeff = ScoreCoeff
	recognizer.EvalMode = int64(EvalMode)
	recognizer.Keyword = ""
	recognizer.SentenceInfoEnabled = 0
	recognizer.TextMode = 0
	recognizer.RecMode = 1

	// 握手阶段
	err = recognizer.Start()
	if err != nil {
		return fmt.Errorf("识别失败, 原因: %v\n", err)
	}

	seq := 0
	if RecFlag == 1 {
		// 录音识别模式可以一次性发送全部数据
		fileDataAll, err := os.ReadFile(file)
		if err != nil {
			return fmt.Errorf("读取文件失败：%v\n", err)
		}
		if err = recognizer.Write(fileDataAll); err != nil {
			return fmt.Errorf("写入数据失败：%v\n", err)
		}
	} else {
		// 流式识别模式，需要分片发送音频数据
		for {
			data := make([]byte, SliceSize)
			n, err := audio.Read(data)
			if err != nil {
				if err.Error() == "EOF" {
					break
				}

				helper.Exce("读取文件失败：%v\n", err.Error())

				break
			}
			if n <= 0 {
				break
			}

			err = recognizer.Write(data)
			if err != nil {
				break
			}
			// 模拟真实场景，200ms产生200ms数据
			time.Sleep(200 * time.Millisecond)
			seq++
		}
	}

	recognizer.Stop()

	return nil
}
